const Websocket = require('ws')

const wss = new Websocket.Server({ port: 3000 })

// 1、建立连接
// 2、关闭连接（退出登录、client 端关闭网页、client 断网）
// 3、业务逻辑：向 client 端推送待办数量
// 4、心跳保活
// 5、消息必达

// 待办事项字段 type
const TodoType = 'todo'
const heartCheckType = 'ping'
// ws <=> client
const clientMap = new Map()
// client 端，心跳保活信息
const heartCheckInfo = {
	type: heartCheckType,
}

function handleMessage(messageStr) {
	console.log('[receive client message]: ', messageStr)
	const message = JSON.parse(messageStr)
	const ws = this

	// 业务逻辑处理：待办数量
	if (message.type === TodoType) {
		const clientMapKeys = Array.from(clientMap.keys())
		const ids = clientMapKeys.map((key) => key.id)
		if (!ids.includes(message.id)) {
			clientMap.set(message, ws)
		}

		// 模拟后端待办数量变更，给前端推送数据
		setInterval(() => {
			triggerEvent()
		}, 3000)
	} else if (message.type === heartCheckType) {
		ws.send(JSON.stringify(heartCheckInfo))
	}
}

// e = 1001
function handleClose(e) {
	// 清除定时器、清除 ws 实例
	let clientKey = null
	for (let [key, value] of clientMap) {
		if (value === this) {
			clientKey = key
			break
		}
	}
	if (clientKey) {
		clientMap.delete(clientKey)
	}
}

function handleError(error) {
	// 错误上报
	console.log('error', error)
}

// 业务端某个账户待办数量变更
const newTodoNum = {
	id: '001',
	name: '张三',
	todoNum: 3,
	type: TodoType,
}
function triggerEvent() {
	newTodoNum.todoNum++
	const { id, todoNum } = newTodoNum
	const clientMapKeys = Array.from(clientMap.keys())
	if (clientMapKeys.length) {
		const mapKey = clientMapKeys.find((key) => key.id === id)
		if (mapKey) {
			const ws = clientMap.get(mapKey)
			// 待办数量不一样推送
			if (mapKey.todoNum !== todoNum) {
				ws.send(JSON.stringify(newTodoNum))
			}
		}
	}
}

wss.on('connection', (ws) => {
	ws.send(JSON.stringify('message from server: 连接成功'))
	ws.on('message', handleMessage)
	ws.on('close', handleClose)
	ws.on('error', handleError)

	ws.ping
})
